//
//  RDLinkedInEngine.m
//  LinkedInClientLibrary
//
//  Created by Sixten Otto on 12/30/09.
//  Copyright 2010 Results Direct. All rights reserved.
//

#import "OAuthConsumer.h"
#import "FOAuthDelegate.h"
#import "FOAuthEngine.h"


@interface FOAuthEngine ()

- (void)sendTokenRequestWithURL:(NSURL *)url token:(OAToken *)token onSuccess:(SEL)successSel onFail:(SEL)failSel;

@end


@implementation FOAuthEngine

@synthesize verifier = oAuthVerifier;

+ (id)engineWithConsumerKey:(NSString *)consumerKey consumerSecret:(NSString *)consumerSecret delegate:(id<FOAuthDelegate>)delegate {
  return [[self alloc] initWithConsumerKey:consumerKey consumerSecret:consumerSecret delegate:delegate];
}

- (id)initWithConsumerKey:(NSString *)consumerKey consumerSecret:(NSString *)consumerSecret delegate:(id<FOAuthDelegate>)delegate {
  self = [super init];
  if( self != nil ) {
    oAuthDelegate = delegate;
    oAuthConsumer = [[OAConsumer alloc] initWithKey:consumerKey secret:consumerSecret];
  }
  return self;
}

#pragma mark authorization methods

- (BOOL)isAuthorized {
  if( oAuthAccessToken.key && oAuthAccessToken.secret ) return YES;
  
  // check for cached creds
  if( [oAuthDelegate respondsToSelector:@selector(oAuthEngineAccessToken:)] ) {
		oAuthAccessToken = nil;
		oAuthAccessToken = [oAuthDelegate oAuthEngineAccessToken:self];
    if( oAuthAccessToken.key && oAuthAccessToken.secret ) return YES;
  }
  
  oAuthAccessToken = nil;
  return NO;
}

- (BOOL)hasRequestToken {
  return (oAuthRequestToken.key && oAuthRequestToken.secret);
}

- (void)requestRequestToken {
  [self sendTokenRequestWithURL:[NSURL URLWithString:kOAuthRequestTokenURL]
                          token:nil
                      onSuccess:@selector(setRequestTokenFromTicket:data:)
                         onFail:@selector(oauthTicketFailed:data:)];
}

- (void)requestAccessToken {
  [self sendTokenRequestWithURL:[NSURL URLWithString:kOAuthAccessTokenURL]
                          token:oAuthRequestToken
                      onSuccess:@selector(setAccessTokenFromTicket:data:)
                         onFail:@selector(oauthTicketFailed:data:)];
}

- (void)requestTokenInvalidation {
  [self sendTokenRequestWithURL:[NSURL URLWithString:kOAuthInvalidateURL]
                          token:oAuthRequestToken
                      onSuccess:@selector(tokenInvalidationSucceeded:data:)
                         onFail:@selector(oauthTicketFailed:data:)];
}

- (NSURLRequest *)authorizationFormURLRequest {
  OAMutableURLRequest *request = [[OAMutableURLRequest alloc] initWithURL:[NSURL URLWithString:kOAuthAuthorizeURL] consumer:nil token:oAuthRequestToken realm:nil signatureProvider:nil];
  [request setParameters: [NSArray arrayWithObject: [[OARequestParameter alloc] initWithName:@"oauth_token" value:oAuthRequestToken.key]]];	
  return request;
}

- (void)sendTokenRequestWithURL:(NSURL *)url token:(OAToken *)token onSuccess:(SEL)successSel onFail:(SEL)failSel {
  OAMutableURLRequest* request = [[OAMutableURLRequest alloc] initWithURL:url consumer:oAuthConsumer token:token realm:nil signatureProvider:nil];
	if( !request ) return;
	
  [request setHTTPMethod:@"POST"];
	if( oAuthVerifier.length ) token.pin = oAuthVerifier;
	
  OADataFetcher* fetcher = [[OADataFetcher alloc] init];	
  [fetcher fetchDataWithRequest:request delegate:self didFinishSelector:successSel didFailSelector:failSel];
}

- (void)oauthTicketFailed:(OAServiceTicket *)ticket data:(NSData *)data {
  // notification of authentication failure
	if( [oAuthDelegate respondsToSelector:@selector(oAuthEngineFailureAccessToken:data:)] ) {
		[oAuthDelegate oAuthEngineFailureAccessToken:ticket data:data];
	}
	
}

- (void)setRequestTokenFromTicket:(OAServiceTicket *)ticket data:(NSData *)data {
  NSLog(@"got request token ticket response: %@ (%lu bytes)", ticket, (unsigned long)[data length]);
  if (!ticket.didSucceed || !data) return;
  
  NSString *dataString = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
  if (!dataString) return;
  
  oAuthRequestToken = [[OAToken alloc] initWithHTTPResponseBody:dataString];
  NSLog(@"  request token set %@", oAuthRequestToken.key);
  
  if( oAuthVerifier.length ) oAuthRequestToken.pin = oAuthVerifier;
}

- (void)setAccessTokenFromTicket:(OAServiceTicket *)ticket data:(NSData *)data {
  NSLog(@"got access token ticket response: %@ (%lu bytes)", ticket, (unsigned long)[data length]);
  if (!ticket.didSucceed || !data) return;
  
  NSString *dataString = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
  if (!dataString) return;
  
  if( oAuthVerifier.length && [dataString rangeOfString:@"oauth_verifier"].location == NSNotFound ) {
    dataString = [dataString stringByAppendingFormat:@"&oauth_verifier=%@", oAuthVerifier];
  }
  
  oAuthAccessToken = [[OAToken alloc] initWithHTTPResponseBody:dataString];
  //RDLOG(@"  access token set %@", oAuthAccessToken.key);
  
  if( [oAuthDelegate respondsToSelector:@selector(oAuthEngineAccessToken:setAccessToken:)] ) {
    [oAuthDelegate oAuthEngineAccessToken:self setAccessToken:oAuthAccessToken];
  }
}


- (void)tokenInvalidationSucceeded:(OAServiceTicket *)ticket data:(NSData *)data {
  oAuthAccessToken = nil;
  
  NSHTTPCookieStorage* cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
  for( NSHTTPCookie *c in [cookieStorage cookies] ){
    if( [[c domain] hasSuffix:@".linkedin.com"] ) {
      [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:c];
    }
  }
  
  if( [oAuthDelegate respondsToSelector:@selector(oAuthEngineAccessToken:setAccessToken:)] ) {
    [oAuthDelegate oAuthEngineAccessToken:self setAccessToken:nil];
  }
}

- (BOOL) isOAuthCallBackURL:(NSString *)hostName{
	return NO;
}

- (BOOL)isOAuthCancelCallBackURL:(NSString *)hostName{
	return NO;
}

- (OAMutableURLRequest *)profileForCurrentUser {
	return nil;
	NSURL* url = [NSURL URLWithString:[kAPIBaseURL stringByAppendingString:@"/v1/people/~:(id)"]];
	OAMutableURLRequest *request = [self sendAPIRequestWithURL:url HTTPMethod:@"GET" body:nil];
    
    return request;
    
}

- (OAMutableURLRequest *)sendAPIRequestWithURL:(NSURL *)url HTTPMethod:(NSString *)method body:(NSData *)body {
	if( !self.isAuthorized ) return nil;
	
	// create and configure the URL request
	OAMutableURLRequest* request = [[OAMutableURLRequest alloc] initWithURL:url consumer:oAuthConsumer token:oAuthAccessToken realm:nil  signatureProvider:nil];
	[request setHTTPShouldHandleCookies:NO];
	[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
	if( method ) {
		[request setHTTPMethod:method];
	}
	
	// prepare the request before setting the body, because OAuthConsumer wants to parse the body
	// for parameters to include in its signature, but LinkedIn doesn't work that way
	[request prepare];
	if( [body length] ) {
		[request setHTTPBody:body];
	}
	
	return request;
}
@end
